﻿using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.AspNetCore.Mvc;
using Microsoft.AspNetCore.Mvc.Rendering;
using Microsoft.AspNetCore.Mvc.ViewEngines;
using Microsoft.AspNetCore.Mvc.ViewFeatures;
using MiniFox.Components;
using MiniFox.Configurations;
using MiniFox.Infrastructure;
using MiniFox.Resources;
using MiniFox.Web.Configurations;
using Newtonsoft.Json;
using System.Collections.Specialized;
using System.Net;
using System.Text;
using System.Text.Json;

namespace MiniFox.Web.Infrastructure
{
    /// <summary>
    /// 
    /// </summary>
    public abstract class MvcControllerBase : Controller
    {
        bool _initialized;
        /// <summary>
        /// 
        /// </summary>
        public MvcControllerBase()
        {
            _initialized = false;
            InitializeComponent();
        }

        #region auto load
        private void InitializeComponent()
        {
            if (!this._initialized)
            {
                this.Container.InitInstance(this);
                _initialized = true;
            }
        }
        #endregion

        /// <summary>
        /// 组件容器
        /// </summary>
        protected virtual ComponentContainer Container
        {
            get { return ComponentFactory.Container; }
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        [HttpGet]
        public virtual IActionResult Entry(string name)
        {
            return Entry(name, null);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <param name="model"></param>
        /// <returns></returns>
        [HttpPost]
        public virtual IActionResult Entry(string name, object model)
        {
            if (string.IsNullOrWhiteSpace(name))
            {
                name = "Index";
            }
            return View(name, model);
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected virtual IActionResult ResponseResult(object model)
        {
            return ResponseResult(model, new JsonSerializerSettings
            {
                DateFormatHandling = DateFormatHandling.IsoDateFormat,
                DateParseHandling = DateParseHandling.DateTime,
                Formatting = Formatting.Indented
            });
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="jsonSerializerSettings"></param>
        /// <returns></returns>
        protected virtual IActionResult ResponseResult(object model, JsonSerializerSettings jsonSerializerSettings)
        {
            IActionResult result;
            if (Request.IsAjaxRequest())
            {
                result = Json(model, jsonSerializerSettings);
            }
            else if (model is IRedirectResponse)
            {
                result = Redirect((IRedirectResponse)model);
            }
            else
            {
                result = View(model);
            }
            return result;
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="response"></param>
        /// <returns></returns>
        protected virtual IActionResult Redirect(IRedirectResponse response)
        {
            if (Request.IsAjaxRequest())
            {
                return Json(response);
            }
            else
            {
                string url = response.RedirectUri;
                return base.Redirect(url);
            }
        }

        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <returns></returns>
        protected Task<string> RenderViewAsync(object model)
        {
            return RenderViewAsync(model, null, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="isPartial"></param>
        /// <returns></returns>
        protected Task<string> RenderViewAsync(object model, bool isPartial)
        {
            return RenderViewAsync(model, null, isPartial);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="viewName"></param>
        /// <returns></returns>
        protected Task<string> RenderViewAsync(object model, string viewName)
        {
            return RenderViewAsync(model, viewName, false);
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="viewName"></param>
        /// <param name="isPartial"></param>
        /// <returns></returns>
        protected async Task<string> RenderViewAsync(object model, string viewName, bool isPartial)
        {
            var controllerContext = this.ControllerContext;
            if (string.IsNullOrEmpty(viewName))
            {
                viewName = controllerContext.ActionDescriptor.ActionName;
            }

            ViewData.Model = model;
            StringBuilder stringBuilder = new StringBuilder();
            await using (var sw = new StringWriter(stringBuilder))
            {
                var viewEngine = this.HttpContext.RequestServices.GetService(typeof(IViewEngine)) as IViewEngine;
                ViewEngineResult viewResult = viewEngine.FindView(controllerContext, viewName, !isPartial);
                if (!viewResult.Success)
                {
                    return $"视图'{viewName}'未找到";
                }
                var viewContext = new ViewContext(controllerContext, viewResult.View, ViewData, TempData, sw, new HtmlHelperOptions());

                await viewResult.View.RenderAsync(viewContext);

            }
            return stringBuilder.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="model"></param>
        /// <param name="viewName"></param>
        /// <param name="isPartial"></param>
        /// <returns></returns>
        protected string RenderViewToString(object model, string viewName, bool isPartial)
        {
            var controllerContext = this.ControllerContext;
            if (string.IsNullOrEmpty(viewName))
            {
                viewName = controllerContext.ActionDescriptor.ActionName;
            }
            ViewData.Model = model;
            StringBuilder stringBuilder = new StringBuilder();
            using (var sw = new StringWriter(stringBuilder))
            {
                var viewEngine = this.HttpContext.RequestServices.GetService(typeof(IViewEngine)) as IViewEngine;
                var viewResult = viewEngine.FindView(controllerContext, viewName, !isPartial);
                if (!viewResult.Success)
                {
                    return $"视图'{viewName}'未找到";
                }
                var viewContext = new ViewContext(controllerContext, viewResult.View, ViewData, TempData, sw, new HtmlHelperOptions());
                var task = viewResult.View.RenderAsync(viewContext);
                task.RunSynchronously();
            }
            return stringBuilder.ToString();
        }
        /// <summary>
        /// 
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        [HttpGet]
        public String Resource(string name)
        {
            var content = GetResource(name);
            return content;
        }
        #region 

        /// <summary>
        /// 
        /// </summary>
        /// <param name="resourceName"></param>
        /// <returns></returns>
        protected virtual string GetResource(string resourceName)
        {
            string msg = CommonMessages.ResourceManager.GetString(resourceName);
            return msg;
        }
        #endregion

        /// <summary>
        /// 根据配置自动匹配user agent，且生成过渡跳转链接，新生成的链接中将自动包含源链接所有url参数及hash值(url中#后面的字符)
        /// </summary>
        /// <param name="name"></param>
        /// <returns></returns>
        protected virtual string Via(string name)
        {
            if (string.IsNullOrWhiteSpace(name))
                return string.Empty;
            WebConfiguration webConfiguration = ConfigurationFactory.GetConfig<WebConfiguration>();
            if (webConfiguration.ViaAgents == null || webConfiguration.ViaAgents.Count <= 0)
                return string.Empty;
            var viaAgent = webConfiguration.ViaAgents[name];
            if (viaAgent == null)
                return string.Empty;
            var userAgent = Request.Headers.UserAgent.ToString().ToLower();
            var urlMappings = viaAgent.UrlMappings;

            if (urlMappings == null || urlMappings.Count <= 0)
                return string.Empty;
            string url = null;
            foreach (var kv in urlMappings)
            {
                var key = kv.Key;
                if (userAgent.Contains(key.ToLower()))
                {
                    url = kv.Value;
                    break;
                }
            }
            if (string.IsNullOrWhiteSpace(url))
            {
                return string.Empty;
            }

            url = WebUtil.BuildFullUrl(Request.GetFullHost(), Url.Content(url), Request.Query, Request.GetEncodedUrl().GetHash());

            return url;
        }
    }
}

